package per.jdz.demo.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.text.similarity.CosineSimilarity;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author Jdz
 * @date 2025/1/11
 */
@Slf4j
public class StrUtil {

    private static boolean charReg(char charValue) {
        return (charValue >= 0x4E00 && charValue <= 0X9FA5) || (charValue >= 'a' && charValue <= 'z') || (charValue >= 'A' && charValue <= 'Z') || (charValue >= '0' && charValue <= '9');
    }

    private static String removeSign(String str) {
        StringBuffer sb = new StringBuffer();
        for (char item : str.toCharArray()) {
            if (charReg(item)) {
                sb.append(item);
            }
        }
        return sb.toString();
    }

    public static String longestCommonSubstringNoOrder(String strA, String strB) {
        if (strA.length() >= strB.length()) {
            return longestCommonSubstring(strA, strB);
        } else {
            return longestCommonSubstring(strB, strA);
        }
    }

    private static String longestCommonSubstring(String strLong, String strShort) {
        char[] chars_strA = strLong.toCharArray();
        char[] chars_strB = strShort.toCharArray();
        int m = chars_strA.length;
        int n = chars_strB.length;
        int[][] matrix = new int[m + 1][n + 1];
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (chars_strA[i - 1] == chars_strB[j - 1]) {
                    matrix[i][j] = matrix[i - 1][j - 1] + 1;
                } else {
                    matrix[i][j] = Math.max(matrix[i][j - 1], matrix[i - 1][j]);
                }
            }
        }
        char[] result = new char[matrix[m][n]];
        int currentIndex = result.length - 1;
        while (matrix[m][n] != 0) {
            if (matrix[n] == matrix[n - 1]) {
                n--;
            } else if (matrix[m][n] == matrix[m - 1][n]) {
                m--;
            } else {
                result[currentIndex] = chars_strA[m - 1];
                currentIndex--;
                n--;
                m--;
            }
        }
        return new String(result);
    }


    public static double SimilarDegree(String strA, String strB) {
        String newStrA = removeSign(strA);
        String newStrB = removeSign(strB);
        int temp = Math.min(newStrA.length(), newStrB.length());
        int temp2 = longestCommonSubstringNoOrder(newStrA, newStrB).length();
        BigDecimal similarity = new BigDecimal(temp2)
                .divide(new BigDecimal(temp), 2, RoundingMode.HALF_UP);

        return similarity.doubleValue();
    }

    public static double calculateInclusionPercentage(String str1, String str2) {
        str1 = str1.toLowerCase();
        str2 = str2.toLowerCase();

        // Filter out only Chinese, English letters, and digits
        str1 = filterString(str1);
        str2 = filterString(str2);

        Map<Character, Integer> charCountStr1 = buildCharFrequencyMap(str1);
        Map<Character, Integer> charCountStr2 = buildCharFrequencyMap(str2);

        int matchingCharsCount = 0;
        for (Map.Entry<Character, Integer> entry : charCountStr1.entrySet()) {
            char ch = entry.getKey();
            int countInStr1 = entry.getValue();
            int countInStr2 = charCountStr2.getOrDefault(ch, 0);

            if (countInStr1 <= countInStr2) {
                matchingCharsCount += countInStr1;
            } else {
                matchingCharsCount += countInStr2;
            }
        }

        return str1.isEmpty() ? 0 : ((double) matchingCharsCount / Math.min(str1.length(), str2.length()));
    }

    private static Map<Character, Integer> buildCharFrequencyMap(String str) {
        Map<Character, Integer> frequencyMap = new HashMap<>();
        for (char c : str.toCharArray()) {
            frequencyMap.put(c, frequencyMap.getOrDefault(c, 0) + 1);
        }
        return frequencyMap;
    }

    private static String filterString(String str) {
        // Using regex to retain only Chinese characters, English letters, and digits
        return str.replaceAll("[^\\u4e00-\\u9fa5A-Za-z0-9]", "");
    }

    public static double calculateSimilarity(String input, String target) {
        // 计算两个字符串的最大长度
        int maxLength = Math.max(input.length(), target.length());
        // 使用StringUtils工具类计算Levenshtein距离
        int editDistance = StringUtils.getLevenshteinDistance(input, target);
        // 根据Levenshtein距离计算相似度
        return 1.0 - (double) editDistance / maxLength;
    }

    public static Double getSimilar(String args1, String args2) {
        args1 = ignoreKeyWords(args1);
        args2 = ignoreKeyWords(args2);
        Map<CharSequence, Integer> map = Arrays.stream(args1.split(""))
                .collect(Collectors.toMap(c -> c, c -> 1, Integer::sum));
        Map<CharSequence, Integer> map2 = Arrays.stream(args2.split(""))
                .collect(Collectors.toMap(c -> c, c -> 1, Integer::sum));

        CosineSimilarity cosineSimilarity = new CosineSimilarity();
        Double similar = cosineSimilarity.cosineSimilarity(map, map2);
        return similar;
    }

    public static String ignoreKeyWords(String source) {
        // Barracks 军营 Service Area 服务中心  Air Station 航空站 Air Base 空军基地 Camp 营地 Recreation Center 娱乐中心 Communications Station 通信站
        // Transmitter Site 发射站 Communication Site 通信站点 Training 训练 Airfield机场 Ammunition Depot 弹药库 Port 港口 Pier 码头 Dependent Housing 家属区
        // Depot 仓库 Landing Field 着陆场 Corps 兵团 Naval 海军
        String[] keyWords = {".", "", "・", "(", ")", "·", " "};
        for (String keyword : keyWords) {
            source = source.replace(keyword, "").trim();
        }
        return source;
    }

    public static String extractNumber(String str) {
        if (!StringUtils.isNotBlank(str)) return null;
        String[] split = str.split("-");
        Pattern pattern = Pattern.compile("\\d+");  // 匹配一个或多个数字
        String number;
        if (split.length == 2) {
            Matcher matcher = pattern.matcher(split[0]);
            if (matcher.find()) {
                number = matcher.group();
                return number + "-" + split[1];
            }
            return split[0] + "-" + split[1];
        } else if (split.length == 1) {
            Matcher matcher = pattern.matcher(split[0]);
            if (matcher.find()) {
                number = matcher.group();
                return 1 + "-" + number;
            }
            return 1 + "-" + split[0];
        } else if (split.length == 3) {
            if (split[2].contains("叠")) {
                return split[1] + "-" + "101";
            }
            Matcher matcher = pattern.matcher(split[1]);
            if (matcher.find()) {
                number = matcher.group();
                return number + "-" + split[2];
            }
        }
        log.error("Invalid input string, {}", str);
        return null;
    }

    public static void main(String[] args) {
        String str1 = "金伟柏悦府";
        String str2 = "柏悦府";
        String str3 = "远洋・湖印都会";
//        System.out.println(str3.replace("・", "").trim());
////        System.out.printf("The inclusion percentage is: %.2f%%\n", calculateInclusionPercentage(str1, str2));
//        System.out.println(getSimilar(str1, str2));
//        System.out.println(getSimilar(str2, str1));
        System.out.println(extractNumber("A-1804"));
        System.out.println(extractNumber("A3-4-叠上左"));
        System.out.println(extractNumber("西803"));
        System.out.println(extractNumber("西1单元-301"));
        System.out.println(extractNumber("3#-1-102"));
        System.out.println(extractNumber("东2单元--102".replace("--", "-")));
        System.out.println("4--501".replace("--", "-"));
        System.out.println("3-206(-)".replace("(-)", ""));

        int idx = "27-1-01（一层）".indexOf("（");
        String result = "27-1-01（一层）".substring(0, idx);
        System.out.println(result);
    }

}
